home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #ifdef __TURBOC__
- #include <io.h>
- #include <fcntl.h>
- #endif
- #include "global.h"
- #include "config.h"
- #include "mbuf.h"
- #include "socket.h"
- #include "telnet.h"
- #include "session.h"
- #include "proc.h"
- #include "tty.h"
- #include "commands.h"
- #include "netuser.h"
-
- static int near filemode __ARGS((FILE *fp,int mode));
- static int near gen_telnet __ARGS((char *name, int type, int ipport, int split, int msg, int bbs));
-
- static int Refuse_echo = 0;
- static int Tn_cr_mode = 0; /* if true turn <cr> to <cr-nul> */
-
- #ifdef DEBUG
- char *T_options[] = {
- "Transmit Binary",
- "Echo",
- "",
- "Suppress Go Ahead",
- "",
- "Status",
- "Timing Mark"
- };
- #endif
-
- #ifdef MAILBOX
- /* Execute user BBS command */
- int
- dobbs(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(Ip_addr == 0) {
- tputs(Noipaddr);
- return -1;
- }
- return gen_telnet("LocBBS",TELNET,IPPORT_TELNET,1,0,1);
- }
- #endif
-
- /* Execute user chat command */
- int
- dochat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- strlwr(argv[1]);
- return gen_telnet(argv[1],TELNET,IPPORT_TTYLINK,1,1,0);
- }
-
- /* Execute user telnet command */
- int
- dotelnet(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int split, arg = atoi(argv[2]);
-
- if(argc > 2)
- split = (arg == IPPORT_TTYLINK || arg == IPPORT_CONVERS) ? 1 : 0;
- strlwr(argv[1]);
- return gen_telnet(argv[1],TELNET,(argc < 3) ? IPPORT_TELNET : arg,split,1,0);
- }
-
- static int near
- gen_telnet(name,type,ipport,split,msg,bbs)
- char *name;
- int type;
- int ipport;
- int split;
- int msg;
- int bbs;
- {
- struct session *sp;
- struct sockaddr_in fsocket;
-
- /* Allocate a session descriptor */
- if((sp = newsession(name,type,split,1)) == NULLSESSION) {
- tputs(Nosess);
- return 1;
- }
-
- fsocket.sin_family = AF_INET;
- fsocket.sin_port = ipport;
-
- if(bbs)
- fsocket.sin_addr.s_addr = Ip_addr;
- else {
- if(msg)
- tprintf("Resolving %s... ",sp->name);
- if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
- tprintf(Badhost,sp->name);
- goto quit;
- }
- }
- if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
- tputs(Nosocket);
- goto quit;
- }
- if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
- return 0;
- quit:
- keywait(NULLCHAR,1);
- freesession(sp);
- return 1;
- }
-
- /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
- int
- tel_connect(sp,fsocket,len)
- struct session *sp;
- char *fsocket;
- int len;
- {
- struct telnet tn;
-
- memset((char *)&tn,0,sizeof(tn));
-
- tn.eolmode = Tn_cr_mode;
- tn.session = sp; /* Upward pointer */
- sp->cb.telnet = &tn; /* Downward pointer */
- sockmode(sp->s,SOCK_ASCII); /* Default to ascii mode */
-
- tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
- if(connect(sp->s,fsocket,len) == -1){
- tprintf("%s session failed: %s errno %d\n",
- Sestypes[sp->type], sockerr(sp->s),errno);
- return 1;
- }
- tprintf("%s session connected to %s\n",
- Sestypes[sp->type],sp->name);
- log(sp->s,"%4.4s connect",Sestypes[sp->type]);
- tnrecv(&tn);
- return 0;
- }
-
- /* Telnet input routine, common to both telnet and ttylink */
- void
- tnrecv(tn)
- struct telnet *tn;
- {
- char *cp;
- struct session *sp = tn->session;
- int c, s = sp->s;
-
- /* Fork off the transmit process */
- sp->proc1 = newproc("tel_out",1536,tel_output,0,tn,NULL,0);
-
- /* Process input on the connection */
- while((c = recvchar(s)) != -1){
- if(c != IAC){
- /* Ordinary character */
- /* stripping off the high bit disabled - DB3FL
- if(!tn->remote[TN_TRANSMIT_BINARY])
- c &= 0x7f;
- */
-
- tputc((char)c);
- continue;
- }
- /* IAC received, get command sequence */
- c = recvchar(s);
- switch(c){
- case WILL:
- c = recvchar(s);
- willopt(tn,c);
- break;
- case WONT:
- c = recvchar(s);
- wontopt(tn,c);
- break;
- case DO:
- c = recvchar(s);
- doopt(tn,c);
- break;
- case DONT:
- c = recvchar(s);
- dontopt(tn,c);
- break;
- case IAC: /* Escaped IAC */
- tputc(IAC);
- break;
- }
- }
- quit:
- /* A close was received from the remote host.
- * Notify the user, kill the output task and wait for a response
- * from the user before freeing the session.
- */
- sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
- cp = sockerr(s);
- tprintf("%s session closed: %s at %s",
- Sestypes[sp->type], cp != NULLCHAR ? cp : "EOF",ctime(&currtime));
- killproc(sp->proc1);
- sp->proc1 = NULLPROC;
- close_s(sp->s);
- sp->s = -1;
- keywait(NULLCHAR,1);
- freesession(sp);
- }
-
- /* User telnet output task, started by user telnet command */
- static void
- tel_output(unused,tn1,p)
- int unused;
- void *tn1;
- void *p;
- {
- int c;
- struct telnet *tn = (struct telnet *)tn1;
- struct session *sp = tn->session;
-
- /* Send whatever's typed on the terminal */
- while((c = recvchar(sp->input)) != EOF){
- usputc(sp->s,(char)c);
-
- if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
- putc(c,sp->record);
-
- /* By default, output is transparent in remote echo mode.
- * If eolmode is set, turn a cr into cr-null.
- * This can only happen when in remote echo (raw) mode, since
- * the tty driver normally maps \r to \n in cooked mode.
- */
- if(c == '\r' && tn->eolmode)
- usputc(sp->s,'\0');
-
- if(tn->remote[TN_ECHO])
- usflush(sp->s);
- }
- /* Make sure our parent doesn't try to kill us after we exit */
- sp->proc1 = NULLPROC;
- }
-
- int
- doecho(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(argc < 2)
- tprintf("Echo %s\n",Refuse_echo ? "refuse" : "accept");
- else {
- switch(tolower(*argv[1])) {
- case 'r':
- Refuse_echo = 1;
- break;
- case 'a':
- Refuse_echo = 0;
- break;
- default:
- tputs("Usage: echo <refuse|accept>\n");
- return -1;
- }
- }
- return 0;
- }
-
- /* set for unix end of line for remote echo mode telnet */
- int
- doeol(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(argc < 2)
- tprintf("Eol %s\n",Tn_cr_mode ? "null" : "standard");
- else {
- switch(tolower(*argv[1])) {
- case 'n':
- Tn_cr_mode = 1;
- break;
- case 's':
- Tn_cr_mode = 0;
- break;
- default:
- tputs("Usage: eol <standard|null>\n");
- return -1;
- }
- }
- return 0;
- }
-
- /* The guts of the actual Telnet protocol: negotiating options */
- static void
- willopt(tn,opt)
- struct telnet *tn;
- int opt;
- {
- int ack;
-
- #ifdef DEBUG
- tprintf("recv: will ");
- if(uchar(opt) <= NOPTIONS)
- tprintf("%s\n",T_options[opt]);
- else
- tprintf("%u\n",opt);
- #endif
-
- switch(uchar(opt)){
- case TN_TRANSMIT_BINARY:
- case TN_ECHO:
- case TN_SUPPRESS_GA:
- if(tn->remote[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- if(uchar(opt) == TN_ECHO){
- if(Refuse_echo){
- /* User doesn't want to accept */
- ack = DONT;
- break;
- } else {
- /* Put tty into raw mode */
- tn->session->ttystate.edit = 0;
- tn->session->ttystate.echo = 0;
- sockmode(tn->session->s,SOCK_BINARY);
- sockmode(tn->session->input,SOCK_BINARY);
- sockmode(tn->session->output,SOCK_BINARY);
- if(tn->session->record != NULLFILE)
- filemode(tn->session->record,SOCK_BINARY);
-
- }
- }
- tn->remote[uchar(opt)] = 1;
- ack = DO;
- break;
- default:
- ack = DONT; /* We don't know what he's offering; refuse */
- }
- answer(tn,ack,opt);
- }
-
- static void
- wontopt(tn,opt)
- struct telnet *tn;
- int opt;
- {
- #ifdef DEBUG
- tprintf("recv: wont ");
- if(uchar(opt) <= NOPTIONS)
- tprintf("%s\n",T_options[uchar(opt)]);
- else
- tprintf("%u\n",uchar(opt));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->remote[uchar(opt)] == 0)
- return; /* Already clear, ignore to prevent loop */
- tn->remote[uchar(opt)] = 0;
- if(uchar(opt) == TN_ECHO){
- /* Put tty into cooked mode */
- tn->session->ttystate.edit = 1;
- tn->session->ttystate.echo = 1;
- sockmode(tn->session->s,SOCK_ASCII);
- sockmode(tn->session->input,SOCK_ASCII);
- sockmode(tn->session->output,SOCK_ASCII);
- if(tn->session->record != NULLFILE)
- filemode(tn->session->record,SOCK_ASCII);
- }
- }
- answer(tn,DONT,opt); /* Must always accept */
- }
-
- static void
- doopt(tn,opt)
- struct telnet *tn;
- int opt;
- {
- int ack;
-
- #ifdef DEBUG
- tprintf("recv: do ");
- if(uchar(opt) <= NOPTIONS)
- tprintf("%s\n",T_options[uchar(opt)]);
- else
- tprintf("%u\n",uchar(opt));
- #endif
- switch(uchar(opt)){
- case TN_SUPPRESS_GA:
- if(tn->local[uchar(opt)] == 1)
- return; /* Already set, ignore to prevent loop */
- tn->local[uchar(opt)] = 1;
- ack = WILL;
- break;
- default:
- ack = WONT; /* Don't know what it is */
- }
- answer(tn,ack,opt);
- }
-
- static void
- dontopt(tn,opt)
- struct telnet *tn;
- int opt;
- {
- #ifdef DEBUG
- tprintf("recv: dont ");
- if(uchar(opt) <= NOPTIONS)
- tprintf("%s\n",T_options[uchar(opt)]);
- else
- tprintf("%u\n",uchar(opt));
- #endif
- if(uchar(opt) <= NOPTIONS){
- if(tn->local[uchar(opt)] == 0){
- /* Already clear, ignore to prevent loop */
- return;
- }
- tn->local[uchar(opt)] = 0;
- }
- answer(tn,WONT,opt);
- }
-
- static void
- answer(tn,r1,r2)
- struct telnet *tn;
- int r1,r2;
- {
- char s[3];
-
- #ifdef DEBUG
- switch(r1){
- case WILL:
- tprintf("sent: will ");
- break;
- case WONT:
- tprintf("sent: wont ");
- break;
- case DO:
- tprintf("sent: do ");
- break;
- case DONT:
- tprintf("sent: dont ");
- break;
- }
- if(r2 <= 6)
- tprintf("%s\n",T_options[r2]);
- else
- tprintf("%u\n",r2);
- #endif
-
- s[0] = IAC;
- s[1] = r1;
- s[2] = r2;
- send(tn->session->s,s,3,0);
- }
-
- #ifdef __TURBOC__
- /* Set end-of-line translation mode on file */
- static int near
- filemode(fp,mode)
- FILE *fp;
- int mode;
- {
- int omode;
-
- if(fp == NULLFILE)
- return -1;
-
- omode = (fp->flags & _F_BIN) ? SOCK_BINARY : SOCK_ASCII;
-
- switch(mode){
- case SOCK_BINARY:
- fp->flags = _F_BIN;
- setmode(fileno(fp),O_BINARY);
- break;
- case SOCK_ASCII:
- fp->flags &= ~_F_BIN;
- setmode(fileno(fp),O_TEXT);
- break;
- }
- return omode;
- }
- #else
- static int near
- filemode(fp,mode)
- FILE *fp;
- int mode;
- {
- return 0;
- }
- #endif